#include "FileSystem.h"


#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

#define DEVINFOARRAY(d,ofs) ((iop_device_t **)((d)->text_start + (d)->text_size + (d)->data_size + (ofs)))

// buffer used for concating filenames internally
static char buffer[512];


void FileSystem_Create( FSContext* pContext )
{
	strcpy(pContext->m_Path,"/");
	pContext->m_iFile = -1;
	pContext->m_pDir = NULL;
}

void FileSystem_Destroy( FSContext* pContext )
{
	FileSystem_Close(pContext);
}

int FileSystem_OpenFile( FSContext* pContext, const char* pFile, FileMode eMode, int iContinue )
{
	int flags;

	FileSystem_Close(pContext);
	FileSystem_BuildPath( buffer, pContext->m_Path, pFile );

	switch( eMode )
	{
		case FM_READ: flags = O_RDONLY; break;
		case FM_WRITE: flags = O_CREAT|O_TRUNC|O_WRONLY; break;

		default:
			return -1;
	}

	if( (pContext->m_iFile = open(buffer,flags,S_IRWXU|S_IRGRP)) < 0 )
		return -1;

	return 0;
}

int FileSystem_OpenDir( FSContext* pContext, const char* pDir )
{
	FileSystem_Close(pContext);
	FileSystem_BuildPath( buffer, pContext->m_Path, pDir );


	strcpy(pContext->m_List,buffer);

	pContext->m_pDir = opendir(pContext->m_List);
	return pContext->m_pDir ? 0 : -1;
}

int FileSystem_ReadFile( FSContext* pContext, char* pBuffer, int iSize )
{
	if( pContext->m_iFile < 0 )
		return -1;

	return read(pContext->m_iFile,pBuffer,iSize);
}

int FileSystem_WriteFile( FSContext* pContext, const char* pBuffer, int iSize )
{
	if( pContext->m_iFile < 0 )
		return -1;

	return write(pContext->m_iFile,pBuffer,iSize);
}

int FileSystem_ReadDir( FSContext* pContext, FSFileInfo* pInfo )
{
	struct dirent* ent;
	struct tm* t;
	struct stat s;

	memset( pInfo, 0, sizeof(FSFileInfo) );
	pInfo->m_TS.m_iYear = 1970;
	pInfo->m_TS.m_iMonth = 1;
	pInfo->m_TS.m_iDay = 1;

	if( NULL == pContext->m_pDir )
		return -1;

	ent = readdir(pContext->m_pDir);

	if( !ent )
		return -1;

	strcpy(pInfo->m_Name,ent->d_name);

	// get file info
	strcpy( buffer, pContext->m_List );
	strcat( buffer, pInfo->m_Name );

	if( stat( buffer, &s ) < 0 )
		return -1;

	pInfo->m_eType = S_ISDIR(s.st_mode) ? FT_DIRECTORY : S_ISLNK(s.st_mode) ? FT_LINK : FT_FILE;
	pInfo->m_iSize = s.st_size;

	t = localtime(&s.st_mtim);

	pInfo->m_TS.m_iYear = t->tm_year+1900;
	pInfo->m_TS.m_iMonth = t->tm_mon+1;
	pInfo->m_TS.m_iDay = t->tm_mday;

	pInfo->m_TS.m_iHour = t->tm_hour;
	pInfo->m_TS.m_iMinute = t->tm_min;

	pInfo->m_iProtection = s.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO);

	return 0;
}


int FileSystem_CreateDir( FSContext* pContext, const char* pDir )
{
	FileSystem_BuildPath( buffer, pContext->m_Path, pDir );

	return -1;
}

int FileSystem_DeleteDir( FSContext* pContext, const char* pDir )
{
	FileSystem_BuildPath( buffer, pContext->m_Path, pDir );

	return -1;
}


void FileSystem_Close( FSContext* pContext )
{
	if( pContext->m_iFile >= 0 )
	{
		close( pContext->m_iFile );
		pContext->m_iFile = -1;
	}

	if( NULL != pContext->m_pDir )
	{
		closedir( pContext->m_pDir );
		pContext->m_pDir = NULL;
	}
}

void FileSystem_BuildPath( char* pResult, const char* pOriginal, const char* pAdd )
{
	pResult[0] = '\0';

	// absolute path?
	if(pAdd[0] == '/')
	{
		pOriginal = pAdd;
		pAdd = NULL;
	}

	strcat(pResult,"./");

	if( pOriginal )
		strcat(pResult,pOriginal);

	if( pAdd )
	{
		if( (pResult[strlen(pResult)-1] != '/') && (pResult[strlen(pResult)-1] != ':') )
			strcat( pResult, "/" );

		strcat(pResult,pAdd);
	}
}

int FileSystem_ChangeDir( FSContext* pContext, const char* pPath )
{
	strcpy(buffer,pPath);

	if( pPath[0] == '/' )
	{
		strcpy(pContext->m_Path,pPath);
		if( (pContext->m_Path[strlen(pContext->m_Path)-1] != '/') )
			strcat(pContext->m_Path,"/");
	}
	else
	{
		char* entry = strtok(buffer,"/");

		while(entry && strlen(entry)>0)
		{
			if(!strcmp(entry,".."))
			{
				char* t = strrchr(pContext->m_Path,'/');
				while( --t >= pContext->m_Path)
				{
					*(t+1) = 0;

					if( *t == '/')
						break;
				}
			}
			else
			{
				strcat( pContext->m_Path, entry );
				strcat( pContext->m_Path, "/" );
			}

			entry = strtok(NULL,"/");
		}
	}

	return 0;
}
